﻿using System;
using System.Data.EntityClient;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using Framework;
using ISSMoviePlex.DAL.Models;
using ISSMoviePlex.DAL.Repositories;
using System.Data;
using System.Web;
using System.IO;

namespace ISSMoviePlex.DAL
{
    /*
     * Use GENERIC PATTERN
     * TK: Key Of Object
     * TE: Entity
     * TR: Repository
     */
    public abstract class BaseRepository<TK, TE, TR> : IRepository<TE>
        where TE : class
        where TR : BaseRepository<TK, TE, TR>, new()
    {
        protected static string CONNECTION_STRING = @"data source=.\SQLEXPRESS;Initial Catalog=ISSMovieplex;Integrated Security=SSPI;";
        public bool IsUnitTest = false;
        protected ISSMovieplexEntitiesContext Context;
        private IObjectSet<TE> _objectSet;

        private static readonly TR _instance = new TR();

        /*
         * Kien: SINGLETON PATTERN to resolve dependencies issue
         */
        public static TR Instance { get { return _instance; } }

        public void Initialize()
        {
            Context = new ISSMovieplexEntitiesContext(new EntityConnection("metadata=res://*/Models.ISSMovieplexModel.csdl|res://*/Models.ISSMovieplexModel.ssdl|res://*/Models.ISSMovieplexModel.msl;provider=System.Data.SqlClient;provider connection string=\";{0}App=EntityFramework\";".FormatWith(CONNECTION_STRING)));
            /*
             * Kien: DATA MOCKING UNIT TEST
             */
            if (IsUnitTest)
            {
                _objectSet = new InMemoryObjectSet<TE>();
            }
            else
            {
                _objectSet = Context.CreateObjectSet<TE>();
            }


            ResolveDependencies();
        }

        public IQueryable<TE> GetAll()
        {
            return _objectSet;
        }

        public IQueryable<TE> FindBy(Expression<Func<TE, bool>> predicate)
        {
            return _objectSet.Where(predicate);
        }

        public void Add(TE entity)
        {
            _objectSet.AddObject(entity);
        }

        public void Delete(TE entity)
        {
            _objectSet.Attach(entity);
            _objectSet.DeleteObject(entity);
        }

        public void Edit(TE entity)
        {
            _objectSet.Attach(entity);
            Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
        }

        public void Save()
        {
            Context.SaveChanges();
        }

        public abstract TE FindById(TK id);
        public virtual void ResolveDependencies() { }
    }
}
